<?php
/**
 * @name CAPTCHA: Captcha Image Generator
 * @version 0.3, December 14, 2009
 * @copyright &copy; 2009 Novachok, A.
 * @author Snow (Novachok Alexandr) <snow@artinet.com.ua>
 * @package Captcha Control Class
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 */


class Captcha extends meccanoFilters
{
   var $serial      = "20091214";
   var $version     = "0.3";

   var $jpg_enabled = false;
   var $png_enabled = false;

   var $length      = 5;
   var $type        = 'png';
   var $symbols     = "ABCDEFGHIJKLNMPQRSTUVWXYZ123456789";
   var $lines       = true;
   var $noize       = true;
   var $angle       = 20;
   var $fontsize    = 20;
   var $fontname    = null;
   var $imgheight   = 70;
   var $bgcolor     = array('255','255','255');
   var $textcolor   = false;
   var $casesense   = false;

   var $error       = null;

   /**
    * Constructor
    *
    * @param array $params
    */
   function __construct($params = false)
   {
      $check_gd = gd_info();
      if (!$check_gd['GD Version']) {
         $this->error[] = "GD is not installed!";
      }

      if (!empty($check_gd['JPG Support'])) {
         $this->jpg_enabled = true;
      }

      if ($check_gd['PNG Support']) {
         $this->png_enabled = true;
      }

      if(isset($params['font']) && file_exists($params['font']))
      {
         $this->fontname = $params['font'];
      } elseif(isset($params['font']) && file_exists(ROOT . LIBRARY .'/fonts/'. $params['font']))
      {
         $this->fontname = ROOT . LIBRARY .'/fonts/'. $params['font'];
      } else
      {
         $this->error[] = "Can't find Font file";
      }

      $this->lines = config::read('cp_lines');
      $this->noize = config::read('cp_noize');
      $this->angle = config::read('cp_angle');

      if(is_array($params))
      {
         foreach ($params as $key=>$value)
         {
            $key = $this->getFirstAlpha($key);
            if($key)
            {
               switch ($key)
               {
                  case 'length':
                     if($this->isValidInteger($value)) $this->length = $value;
                     break;

                  case 'symbols':
                     if($this->isValidAlpha($value)) $this->symbols = $value;
                     break;

                  case 'type':
                     $value = $this->getFirstAlpha($value);
                     if($value == 'png' && $this->png_enabled == true) $this->type = $value;
                     if($value == 'jpeg' && $this->jpg_enabled == true) $this->type = $value;
                     break;

                  case 'lines':
                     $this->lines = $this->isValidBool($value);
                     break;

                  case 'noize':
                     $this->noize = $this->isValidBool($value);

                  case 'angle':
                     if($this->isValidInteger($value)) $this->angle = $value;
                     break;

                  case 'indent':
                     if($this->isValidInteger($value)) $this->indent = $value;
                     break;

                  case 'fontsize':
                     if($this->isValidInteger($value)) $this->fontsize = $value;
                     break;

                  case 'imgheight':
                     if($this->isValidInteger($value)) $this->imgheight = $value;
                     break;

                  case 'casesens':
                     $this->casesense = $this->isValidBool($value);
                     break;

                  case 'bgcolor':
                     if($this->isValidHexColor($value))
                     {
                        $value = strlen($value) == 7 ? substr($value, 1) : $value;
                  	$this->bgcolor[0] = hexdec(substr($value, 1,2));
                  	$this->bgcolor[1] = hexdec(substr($value, 3,2));
                  	$this->bgcolor[2] = hexdec(substr($value, 5,2));
                     }
                     break;

                  case 'textcolor':
                     if($this->isValidHexColor($value))
                     {
                        $value = strlen($value) == 7 ? substr($value, 1) : $value;
                        $this->textcolor = array();
                        $this->textcolor[0] = hexdec(substr($value, 0,2));
                        $this->textcolor[1] = hexdec(substr($value, 2,2));
                        $this->textcolor[2] = hexdec(substr($value, 4,2));
                     }
                     break;
               }
            }
         }
      }

      register_shutdown_function(array(&$this, "__destruct"));
   }

   function Captcha($font, $params)
   {
      $this->__construct($font, $params);
   }

   function __destruct()
   {
   }

   /**
    * Generate Captcha image
    *
    * @return bool
    */
   function createCaptcha()
   {
      if($this->error !== null) return false;
      if($this->jpg_enabled == false && $this->png_enabled == false)
      {
         $this->error[] = "Can't save JPG or PNG either. Check your GD configuration.";
         return false;
      }

      $img_width = $this->length * ($this->fontsize + 7);
      $image     = imagecreatetruecolor($img_width, $this->imgheight) or die("Cannot Initialize new GD image stream");
      $bgcolor   = imagecolorallocate($image, $this->bgcolor[0], $this->bgcolor[1], $this->bgcolor[2]);
      imagefill($image,0,0,$bgcolor);

      if($this->noize == true)
      {
         $rand_pix  = $img_width * $this->imgheight / 2;
         for($i=0; $i<$rand_pix; $i++)
         {
            $color_pix  = ImageColorAllocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            ImageSetPixel($image, rand(0, $img_width), rand(0, $this->imgheight), $color_pix);
         }
         imagefilter($image, IMG_FILTER_SMOOTH, 10);
      }

      $str = $this->createString();
      for($i=0; $i<$this->length; $i++)
      {
         if(!$this->textcolor)
         {
            $color_str = imagecolorallocate($image, mt_rand(0, 180), mt_rand(0, 100), mt_rand(0, 180));
         } else
         {
            $color_str = imagecolorallocate($image, $this->textcolor[0], $this->textcolor[1], $this->textcolor[2]);
         }

         imagettftext($image,
         $this->fontsize,
         mt_rand(-$this->angle,$this->angle),
         10 + (($this->fontsize + 4) * $i),
         mt_rand(round($this->fontsize+($this->imgheight/10)), $this->fontsize+5),
         $color_str,
         $this->fontname, $str{$i});
      }

      if($this->lines == true)
      {
         $this->drawLines($image, $img_width);
      }

      if($this->type == 'jpeg')
      {
         header('Content-Type: image/jpeg');
         imagejpeg($image);
      } elseif($this->type == 'png')
      {
         header('Content-Type: image/png');
         imagepng($image);
      }

      imagedestroy($image);

      return true;
   }


   /**
    * Check unswer of captcha
    *
    * @param string $str
    * @return bool
    */
   function verifyCaptcha($str)
   {
      $captcha_session_var = config::read('cp_variable') ? config::read('cp_variable') : FALSE;
      $captcha_session_var = !$captcha_session_var ? 'captcha' : $captcha_session_var;

      $saved_string = session::getVar($captcha_session_var);

      if($this->casesense == false) $str = strtoupper($str);

      if($str == $saved_string) return true;
      return false;
   }

   /**
    * Generate random string
    *
    * @return string
    */
   function createString()
   {
      $str = "";
      for ($i=0; $i<$this->length; $i++)
      {
         $str .= $this->symbols{mt_rand (0, strlen($this->symbols)-1)};
      }
      if($this->casesense == false) $str = strtoupper($str);

      $captcha_session_var = config::read('cp_variable') ? config::read('cp_variable') : FALSE;
      $captcha_session_var = !$captcha_session_var ? 'captcha' : $captcha_session_var;

      session::setVar($captcha_session_var, $str);

      return $str;
   }

   /**
    * Drow lines on image
    *
    * @param string $image Image descriptor
    * @param integer $img_width with of image
    * @return string Image descriptor
    */
   function drawLines(&$image, $img_width)
   {
      for ($i =0 ; $i<4 ; $i++)
      {
         $color_line = imagecolorallocate($image,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255));

         $x0 = mt_rand(0, 0.5 * $img_width);
         $y0 = mt_rand(0, $this->imgheight);

         $x1 = mt_rand(0.5 * $img_width,$img_width);
         $y1 = mt_rand(0, $this->imgheight);

         imageline($image, $x0, $y0, $x1, $y1,$color_line);
         imageline($image, $x0-1, $y0-1, $x1-1, $y1-1,$color_line);
      }

      return $image;
   }
}